;-------------------------------------------------------------------------
; CONV: implementeren van type-overgangen tussen strings en cardinals
;-------------------------------------------------------------------------
; Dit programma heeft als doel om
	; het omzetten van een string naar cardinal en het resultaat te printen
	; het omzetten van een cardinal naar string en het resultaat te printen
;opmerkingen
	; !! main staat in commentaar activeer het gewenste blok
	
.MODEL small ;one data, one code segment, stack and data segment are grouped
.STACK 1024 ;stack, 1024 bytes
;------------- macros -------------
MPrintString macro string
	push ax
	push dx
	mov ah,09h
		mov dx,offset string
	int 21h
	pop dx
	pop ax
endm

.DATA ;data segment, static variables
;--- constants
	stringlength=2
;--- variables
	string1 db "104$"
	string2 db stringlength dup(?),"$"
	endl db 0Ah,0Dh,"$"
;--- printint procedure data
	powersoften dw 10000,1000,100,10,1
	maxint db "-32768$"

.CODE ;code segment
.STARTUP ; start main, sets ds to beginning of data segment, updates ss to ds and adjusts sp acordingly

; activate this part to test PConvStringToCardinal
	; xor ax,ax
	; push ax				; make space for return value
	; lea ax, string1		; get start address of string
	; push ax  				; push input: start address 
	; mov ax,stringlength
	; push ax				; push input: number of chars
	; call PConvStringToCardinal
	; call printint
	
; activate this part to test PConvCardinalToString
	; lea ax, string2
	; push ax
	; mov ax,102
	; push ax
	; call PConvCardinalToString
	; MPrintString string2

.EXIT ; end main/exit to dos

;--- procedures
	
	nrchar 		equ bp+4
	intnr 		equ bp+4
	startadr 	equ bp+6
	returnv	 	equ bp+8
	
PConvStringToCardinal proc near
; this procedure will convert a string to an integer
;	input:	the start address of string
;			the number of chars
;	ouput:	the integer result 
	
	; procedure datamanagement
	push bp				; save previous base pointer
	mov bp,sp			; update base pointer
	; saving context
	push ax
	push bx
	push dx
	push si
	push di
	push cx
	; fetch input
	mov dx,[nrchar]		; fetch number of chars
	mov si,[startadr]	; fetch start address of string
	; init values
	mov cx,1			; cx=for counter
	mov di,0			; di=result
	; for cx= 1 to number of chars
	CSTIfor1:	
		mov al,[si]			; al = next char of string 
		sub al,48			; convert ASCII code to digit 
		cbw					; ax=ah:al extend byte al to word ax
		mov bx,ax 			; free ax for temporary use
		mov ax,di			; di is now free 
		mov di,10			; temporary use of dx
		push dx				; mul changes the value of dx
		mul di 				; ax=previous result*10
		pop dx
		add ax,bx	        ; ax=previous result*10+new digit
		mov di,ax			; result = previous result*10+ new digit
		inc si				; increase si
		inc cx				; increase counter	
		cmp cx,dx
	jng CSTIfor1
	mov [returnv],di
	;restore context
	pop cx
	pop di
    pop si
    pop dx
    pop bx
    pop ax
    ;restore bp
    pop bp
	;return and freeing param from stack (4 bytes)
    ret 4
PConvStringToCardinal endp




PConvCardinalToString proc
 ;	procedure datamanagement
	push bp				; save previous base pointer
	mov bp,sp			; update base pointer
	; saving context
	push ax
	push dx
	push cx
	push si
	push di
	; fetch input
	mov cx,[intnr]		; fetch integer
	mov di,[startadr]	; fetch start address of string
	; init values
	mov si,offset powersoften	; cx= highest power of ten	
	; if integer=0 special treatment
	add  si,8	; make sure the procedure ends when cx=0
	cmp cx,0
	je CITSwhile1end
	; init values
	mov si,offset powersoften	; cx= highest power of ten	
	; while (PoT>cx) lower power of ten 
	CITSwhile1:
		cmp [si], cx		
		jng CITSwhile1end
		add si,2
		jmp CITSwhile1
	CITSwhile1end:
	;find left digit
	mov ax,cx				; ax=integer
	cwd	
	div word ptr [si]		; ax=integer/PoT dx=mod
	add ax,48				; go to ASCII
	mov [di],al				; write digit to string
	inc di					; move di to next position in string
	mov cx,dx				; integer=dx
	; if si=1 then cx=last digit
	mov ax,1
	cmp [si],ax	
	je CITSlastdigitreached
	add si,2
	jmp CITSwhile1end
	; end of procedure
	CITSlastdigitreached:
	;restore context
	pop di
    pop si
	pop cx
    pop dx
    pop ax
    ;restore bp
    pop bp
	;return and freeing param from stack (4 bytes)
    ret 4
PConvCardinalToString endp

;print an integer to stdout
;value on tos (16-bit 2's compl)
printint proc near ;near procedure
    ;save dynamic link
    push bp
    ;update bp
    mov bp,sp
    ;save context
    push ax
    push bx
    push dx
    push si
    ;load param in bx
    mov bx,[bp+4] ;near proc, one word return address
    ;handle special case of zero
    test bx,0FFFFh
    jnz printint_nonzero
    mov ah,02h
    mov dl,'0'
    int 21h
    jmp printint_done
printint_nonzero:
    ;handle special case of -32768
    cmp bx,-32768
    jnz printint_notintmin
    mov ah,09h
    mov dx,offset maxint
    int 21h
    jmp printint_done
printint_notintmin:
    ;print sign
    test bx,8000h
    jz printint_positive
    ;if negative,print sign and invert
    ;print sign (int 21h, function 02h)
    mov ah,02
    mov dl,'-'
    int 21h
    ;invert sign of bx
    neg bx
printint_positive:
    ;from now on bx is positive
    ;determine largest power of ten smaller than bx
    ;init si to point to first element of powersoften array
    mov si,offset powersoften
    ; while bx<[si] increment si C: while(bx<powersoften[si]) si++
printint_nextpoweroften:
    cmp bx,[si]
    jge printint_powerfound
    add si,2    
    jmp printint_nextpoweroften
printint_powerfound:
    ;ok now print digits
    mov ax,bx
    cwd ;sign extend to DX:AX (32-bit)
    div word ptr [si]  ;divide DX:AX by current power of ten, result in AX, remainder in DX
    mov bx,dx  ;move remainder to bx
    mov ah,02h ;print al
    mov dl,al
    ;add 48 to convert to ascii
    add dl,48
    int 21h
    ;was this the last digit? i.e. [si]==1
    cmp word ptr [si],1
    je printint_done
    add si,2   ;increment si
    jmp printint_powerfound ;repeat for next digit
printint_done:
    ;restore context
    pop si
    pop dx
    pop bx
    pop ax
    ;restore bp
    pop bp
    ;return freeing param from stack (2 bytes)
    ret 2
printint endp

END 
